#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <sys/epoll.h>
#include<unordered_map>
#include"Epoll.hpp"
#include "Log.hpp"
#include "Socket.hpp"
#include"Connect.hpp"
#include<functional>
using namespace SocketModule;
using namespace LogModule;

#define NUM sizeof(fd_set) * 8

const int gdefaultfd = -1;
#define MAX 4096

using connection_t = std::shared_ptr<Connection> ;

// 最开始的时候，tcpserver只有一个listensockfd


class EpollServer
{
    const static int revs_num = 64;
public:
    EpollServer()
        : _isrunning(false)
        ,_epoller(std::make_unique<Epoller>())
    {
    }
    void Init()
    {
        _epoller->Init();
    }
    bool IsExistsEpoller(int sockfd)
    {
        return _connections.find(sockfd) != _connections.end();
    }
    void InsertEpoller(connection_t& con)
    {
        int tmpsockfd = con->SockfdVal();
        auto iter = _connections.find(tmpsockfd);
        if(iter != _connections.end())
        {
            LOG(LogLevel::DEBUG)<<"该链接已在Epoller里面";
        }
        //1把新来的链接写进unordered_map 进行管理
        //2 把新来的链接写入到内核的epollserver里
        _connections.insert(make_pair(tmpsockfd,con));
        _epoller->Ctrl(EPOLL_CTL_ADD,tmpsockfd,con->GetEvents());
    }
    void Loop()
    {
        _isrunning = true;
        while(_isrunning)
        {
            int n = _epoller->Wait(_revs,revs_num);
            if(n < 0 )
            {
                LOG(LogLevel::ERROR)<<"Wait false ";
                return ;
            }
            for(int i = 0 ; i < n ; i++)
            {
                int tmpfd = _revs[i].data.fd;
                uint32_t revents = _revs[i].events;
                //如果当前文件描述符发生了 错误（EPOLLERR） 或 连接挂起（EPOLLHUP），就进入处理逻辑。
                if((revents & EPOLLERR) || (revents & EPOLLHUP))
                    revents = (EPOLLIN | EPOLLOUT); // 异常事件，转换成为读写事件
                
                if((revents& EPOLLIN) && (IsExistsEpoller(tmpfd)))
                {
                    _connections[tmpfd]->CallRev();
                }
                
                if((revents& EPOLLOUT) && (IsExistsEpoller(tmpfd)))
                {
                     _connections[tmpfd]->CallSend();
                }
            }

        }
        _isrunning = false;
    }
    void Stop()
    {
        _isrunning = false;
    }

private:
    std::unique_ptr<Epoller> _epoller; // 不要忘记初始化
    std::unordered_map<int, connection_t> _connections; // fd: Connection， 服务器内部所有的连接
    bool _isrunning;
    struct epoll_event _revs[revs_num];
};